#ifndef __DIRECTORY__
#define __DIRECTORY__

#include <string>
#include "vmface.h"

namespace xm
{
	class directory_t;

	template < KernelObjectClass KoClass >
	class MountableObject : public KernelObject<KoClass>
	{
	protected:
		std::string			_name;
		optr<directory_t>	_dir;
	public:
		virtual ~MountableObject()
		{
			printf( "KernelObject::~KernelObject %08X : %08X:%s\n", this, Class(), Name() );
			if( !_dir ) return ;
			LPCSTR aName = Name();
			_dir->del_object( aName );
		}
		STDMETHOD_(LPCSTR,Name)() 
		{ 
			if( _name.empty() ) return NULL;
			return _name.c_str(); 
		}
		STDMETHOD(MountOn)(IKernelObject* k)
		{
			if( !k ) 
			{
				_dir.dispose();
				return S_OK;
			}

			if( _dir ) 
				return E_UNEXPECTED;

			directory_t * dir = k->proto<directory_t,KoVolume>();
			if( !dir ) return E_FAIL;
		
			_dir = dir;

			return S_OK;
		};
		STDMETHOD_(IKernelObject*, MountedPlace)()
		{
			return _dir;
		}
		HRESULT set_name( LPCSTR name )
		{
			_name = name ? name : "";
			return S_OK;
		}
		virtual kip_t get_full_path( std::string& full, KernelObjectClass dam_class = KoUnknown )
		{
			typedef std::vector< kop_t > kovector;
			kovector names;
			kop_t parent( _dir );
			while( parent )
			{
				if( dam_class && parent->Class() == dam_class )
					break;

				names.push_back( parent );
				IKernelObject * kop = parent->MountedPlace();
				parent = kop ? kop->proto<directory_t,KoVolume>() : 0;
			}
			
			kovector::reverse_iterator rit = names.rbegin();
			for( ; rit != names.rend(); ++ rit )
			{
				LPCSTR tmp = (*rit)->Name();
				if( tmp ) full.append( tmp );
				full.push_back( '\\' );
			}
			
			if( names.empty() ) full.push_back('\\');
			full.append( Name() );

			return parent;
		}
	};

	class directory_t : public MountableObject<KoDirectory>, UnkBase
	{
	public:

		UNKNOWN_IMP1(IKernelObject);

	protected:
	
		struct ent_name
		{
			IKernelObject* inst;
			ent_name( IKernelObject * p ) : inst(p)
			{}
			bool operator < ( const ent_name& right ) const
			{
				return stricmp( inst->Name(), right.inst->Name() ) < 0 ;
			}
		};

		typedef std::map< ent_name, IKernelObject* > object_map_t;

		struct find_key_t : IKernelObject, UnkBase
		{
			UNKNOWN_IMP1(IKernelObject);
			LPCSTR _name;
			find_key_t( LPCSTR name ) : _name(name) {};
			STDMETHOD_(KernelObjectClass,Class)() { return KoUnknown; };
			STDMETHOD_(LPCSTR,Name)() { return _name; }
			STDMETHOD(MountOn)(IKernelObject* k) { return E_NOTIMPL; };
			STDMETHOD_(IKernelObject*, MountedPlace)() { return NULL; };
			STDMETHOD(Rollback)() { return E_NOTIMPL; };
			STDMETHOD_(UINT32,GetAccess)() { return 0; };
			STDMETHOD(SetAccess)(UINT32 uAccess ) { return E_NOTIMPL; };
			STDMETHOD(UpdateScope)( KoScope scop ) { return E_NOTIMPL; };
		};

		object_map_t	_objects;
		uint32_t		_attr;
	public:

		directory_t() : _attr(0)
		{}
		virtual ~directory_t()
		{}
		virtual long add_object( IKernelObject * obj );
		virtual long del_object( LPCSTR name );
		//template < class T >
		//T * get_tobject( LPCSTR name )
		//{
		//	IKernelObject * op = get_object( name );
		//	if( !op ) return 0;
		//	return op->proto<T>();
		//}
		virtual IKernelObject * get_object( LPCSTR name );
		virtual long clear();
		virtual size_t entries();
		virtual IKernelObject * get_next( LPCSTR name );
	};

	class symbol_link_t : public MountableObject<KoSymbolLink>, UnkBase
	{
	public:
		UNKNOWN_IMP1_(IKernelObject);
		std::string target;
		symbol_link_t( LPCSTR ap )
		{
			if( ap ) target = ap;
		}
		const char * nt_target()
		{
			if( target.empty() ) return NULL;
			return target.c_str();
		}
	};

};

#endif